<script>
import {
  computed,
  defineComponent,
  getCurrentInstance,
  onMounted,
  ref,
  watch,
} from 'vue';
import {
  createNamespace,
  createUniqueId,
  getElementBounding,
  transformSize,
  transformStyleSize,
} from '../utils';

export default defineComponent({
  name: createNamespace('PositionedView')[0],
  options: {
    // https://uniapp.dcloud.io/matter.html#mp
    virtualHost: true,
  },
  props: {
    customStyle: [Object, String],
    /**
     * 文档定位方式，同 css 的 position
     */
    type: {
      type: String,
      default: 'fixed',
      validator(value) {
        return ['fixed', 'absolute', 'relative', 'static'].includes(value);
      },
    },
    /**
     * 位置的快捷选项，仅在top、bottom、left、right未设置时生效
     */
    position: {
      type: String,
      validator: (value) => ['bottom', 'top'].includes(value),
    },
    zIndex: {
      type: [Number, String],
      default: 99,
    },
    top: [String, Number],
    bottom: [String, Number],
    left: [String, Number],
    right: [String, Number],
    bg: String,
    // 底部安全区域
    safeBottom: {
      type: Boolean,
      default: false,
    },
    /**
     * 是否在文档流中标签位置生成一个等高的占位元素
     */
    placeholder: {
      type: Boolean,
      default: false,
    },
  },
  expose: ['calcHeight', 'height'],
  setup(props) {
    const uniqueId = createUniqueId({ prefix: 'fanPositionedView' });
    const height = ref(0);

    const theStyle = computed(() => {
      const {
        customStyle,
        type,
        left,
        right,
        top,
        bottom,
        zIndex,
        position,
        bg,
      } = props;
      let s = `position:${type};z-index:${zIndex};`;
      if (!left && !right && !top && !bottom) {
        if (position === 'bottom') s += `bottom:0;left:0;right:0;`;
        if (position === 'top') s += `top:0;left:0;right:0;`;
      } else {
        left && (s += `left:${transformSize(left)};`);
        right && (s += `right:${transformSize(right)};`);
        top && (s += `top:${transformSize(top)};`);
        bottom && (s += `bottom:${transformSize(bottom)};`);
      }
      bg && (s += `background:${bg};`);
      return transformStyleSize(customStyle) + s;
    });
    const useSafeBottom = computed(() => {
      const { position, safeBottom } = props;
      if (safeBottom === false) return false;
      return safeBottom || position === 'bottom';
    });

    const _this = getCurrentInstance();
    let num = 0
    const calcHeight = async () => {
      if (!props.placeholder) {
        height.value = 0;
        return;
      }
      const rect = await getElementBounding({
        selector: '#' + uniqueId,
        scope: _this,
      });
      num++
      if (!rect?.height && num < 3) {
        setTimeout(calcHeight, 100)
        return
      }
      height.value = rect?.height || 0;
    };
    onMounted(() => {
      setTimeout(calcHeight, 0);
    });
    watch(() => props.placeholder, calcHeight);

    return { uniqueId, height, theStyle, useSafeBottom, calcHeight };
  },
});
</script>

<template>
  <div class="fan-positioned-view">
    <div :id="uniqueId" class="fan-positioned-view__in" :class="{ 'fan-positioned-view--safe': useSafeBottom }"
      :style="theStyle">
      <slot />
    </div>
    <div v-if="height" class="fan-positioned-view__place" :style="{ height: height + 'px' }"></div>
  </div>
</template>

<style lang="less">
.fan-positioned-view {
  &--safe {
    padding-bottom: env(safe-area-inset-bottom);
    box-sizing: content-box;
  }
}
</style>
